<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>

<meta charset="utf-8">
<meta name="generator" content="quarto-1.4.549">

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">


<title>jwdid</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
  width: 0.8em;
  margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 
  vertical-align: middle;
}
</style>


<script src="JWDID_files/libs/clipboard/clipboard.min.js"></script>
<script src="JWDID_files/libs/quarto-html/quarto.js"></script>
<script src="JWDID_files/libs/quarto-html/popper.min.js"></script>
<script src="JWDID_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="JWDID_files/libs/quarto-html/anchor.min.js"></script>
<link href="JWDID_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="JWDID_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="JWDID_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="JWDID_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="JWDID_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">

  <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
  <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>

<script type="text/javascript">
const typesetMath = (el) => {
  if (window.MathJax) {
    // MathJax Typeset
    window.MathJax.typeset([el]);
  } else if (window.katex) {
    // KaTeX Render
    var mathElements = el.getElementsByClassName("math");
    var macros = [];
    for (var i = 0; i < mathElements.length; i++) {
      var texText = mathElements[i].firstChild;
      if (mathElements[i].tagName == "SPAN") {
        window.katex.render(texText.data, mathElements[i], {
          displayMode: mathElements[i].classList.contains('display'),
          throwOnError: false,
          macros: macros,
          fleqn: false
        });
      }
    }
  }
}
window.Quarto = {
  typesetMath
};
</script>

</head>

<body class="fullcontent">

<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">

<main class="content" id="quarto-document-content">




<section id="estimation-of-did-models-using-etwfe" class="level2">
<h2 class="anchored" data-anchor-id="estimation-of-did-models-using-etwfe">Estimation of DID models using ETWFE</h2>
<p>In this section, we describe the Stata command <code>jwdid</code> that implements the estimation of DID models using the ETWFE estimator proposed by <span class="citation" data-cites="Wooldridge2022">@Wooldridge2022</span>. One of the main advantages of <span class="citation" data-cites="Wooldridge2022">@Wooldridge2022</span>’s estimator is that by being a simple extension of the standard FE estimator, it can be easily modified and implemented to allow for other types of non-linear models. As described in <span class="citation" data-cites="wooldridge2022">@wooldridge2022</span>, the ETWFE estimator could be used, for example, to model cases where the dependent variable is binary (logit) or count data (poisson). A second advantage of the ETWFE estimator is that the estimation of the baseline model, is transparent as it does not require the use of specialized software, except for the estimation of fixed effects models. This is in contrast with other DID estimators like the ones proposed by <span class="citation" data-cites="callaway2021">@callaway2021</span>, <span class="citation" data-cites="dechaisemartin2021">@dechaisemartin2021</span>, or <span class="citation" data-cites="kirill2022">@kirill2022</span>, where the bulk of the model estimation is done in the background, with the user having less control and understanding on what is being estimated.</p>
<p>Thanks to this transparency in model specification, <span class="citation" data-cites="yotov2023">@yotov2023</span> propose a large set of recommendations for the analysis of DID models in the context of international trade and Gravity models. On this regard, we present the command <code>jwdid</code> as a flexible command in Stata that allows to consider <span class="citation" data-cites="yotov2003">@yotov2003</span> recommendations for the estimation of DID models, in the framework of trade models.</p>
<section id="base-line-model" class="level3">
<h3 class="anchored" data-anchor-id="base-line-model">Base line model</h3>
<p>As described in <span class="citation" data-cites="Wooldrige2021">@Wooldrige2021</span>, the baseline model for the estimation of the DID model using the ETWFE estimator is the following:</p>
<p><span id="eq-b0"><span class="math display">\[Y_{i,t} = \alpha + \sum_{g \in G} \sum_{t=g}^{T} \theta_{g,t} D_{i,g,t} + \xi_i + \xi_t + \varepsilon_{i,t}
\tag{1}\]</span></span></p>
<p>where <span class="math inline">\(Y_{i,t}\)</span> is the dependent variable, <span class="math inline">\(D_{i,g,t}\)</span> is a dummy that takes the value of 1 if the observation is in the treatment group <span class="math inline">\(g\)</span>, on period <span class="math inline">\(t\)</span> and 0 otherwise. <span class="math inline">\(G\)</span> is a set that indicates at what time treatment started for all observations, and <span class="math inline">\(T\)</span> is the last period of the analysis.</p>
<p><span class="math inline">\(\xi_i\)</span> and <span class="math inline">\(\xi_t\)</span> are sets of fixed effects for the individual and time dimensions, respectively.<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> In this setup, the <span class="math inline">\(\theta_{g,t}\)</span> coefficients represent the average treatment effect that the treatment group <span class="math inline">\(g\)</span> experiences at time <span class="math inline">\(t\)</span> (<span class="math inline">\(ATT(g,t)\)</span>). As described in <span class="citation" data-cites="Wooldridge2021">@Wooldridge2021</span>, allowing for a flexible specification of the <span class="math inline">\(\theta_{g,t}\)</span> avoids the problem of bad controls and negative weights that have been identified in the literature as potential problems in the estimation of DID models using traditional TWFE estimators.</p>
<p>This command can be directly estimated with <code>jwdid</code> using the following syntax:</p>
<p><code>jwdid y, ivar(i) tvar(t) gvar(g)</code></p>
<p>Where <code>y</code> is the dependent variable, <code>ivar(i)</code> is used to identify the individual panel data dimension, <code>tvar(t)</code> identifies the time dimension, and <code>gvar(g)</code> identifies the treatment group. Specifically, for observation <span class="math inline">\(i\)</span>, <span class="math inline">\(g\)</span> would take the value of zero if the panel observation is never treated (within the window of the analysis), and would take a value different from zero to indicate the year that treatment started for unit <span class="math inline">\(i\)</span>. Following standard assumptions, this specification assumes that the treatment is an absorbing status, meaning that once a unit is treated, it remains treated for the rest of the analysis.</p>
<p>By default, <code>jwdid</code> will estimate the baseline model <a href="#eq-b0" class="quarto-xref">Equation&nbsp;1</a> using the <code>reghdfe</code> command (<span class="citation" data-cites="correira">@correira</span>), assuming clustered standard errors at <code>i</code> level. If other level is desired, the user can specify the <code>cluster(cvar)</code> option. While the command does not impose the assumption that the data is a panel, the methodology is designed to work with panel data. In case of repeated crossection, one should instead use the following syntax:</p>
<p><code>jwdid y, tvar(t) gvar(g) [cluster(cvar)]</code></p>
<p>By excluding <code>ivar(i)</code>, the command assumes data is a repeated crossection, proceeding to include group fixed effects only. The <code>cluster(cvar)</code> option is not required, but can be used to request Standard errors to be clusted at the level <code>cvar</code>.</p>
<p>Specifically, this command will estimate the following model:</p>
<p><span id="eq-b1"><span class="math display">\[Y_{i,t} = \alpha + \sum_{g \in G} \sum_{t=g}^{T} \theta_{g,t} D_{i,g,t} + \xi_g + \xi_t + \varepsilon_{i,t}
\tag{2}\]</span></span></p>
<p>This model specification makes the implicit assumption that Parallel trends are satisfied, using all never treated and not-yet treated observations as controls (not included category) for the identification of treatment effects.</p>
<p>If one instead wants to relax this assumption, the user can specify the option <code>never</code>:</p>
<p><code>jwdid y, ivar(i) tvar(t) gvar(g) never</code></p>
<p>Which will estimate the following model:</p>
<p><span id="eq-b2"><span class="math display">\[Y_{i,t} = \alpha +  \sum_{g \in G} \sum_{t=t_0}^{g-1} \theta^{pre}_{g,t} D_{i,g,t}+ \sum_{g \in G} \sum_{t=g}^{T} \theta^{post}_{g,t} D_{i,g,t} + \xi_i + \xi_t + \varepsilon_{i,t}
\tag{3}\]</span></span></p>
<p>This is in principle the same as strategy as the one proposed by <span class="citation" data-cites="sunabraham2021">@sunabraham2021</span>, allowing for full heterogeneity across all groups and all relative periods. This specification is also numerically identical to the one proposed by <span class="citation" data-cites="callaway2021">@callaway2021</span>, for the case where there are no covariates. In this case, the only observations that are used as controls are the ones that were never treated. In this specification, all <span class="math inline">\(\theta^{pre}_{g,t}\)</span> can be used to test for the parallel trends assumption, and all <span class="math inline">\(\theta^{post}_{g,t}\)</span> can be used to estimate the treatment effects.</p>
</section>
<section id="extensions-nonlinear-models" class="level3">
<h3 class="anchored" data-anchor-id="extensions-nonlinear-models">Extensions: Nonlinear models</h3>
<p>As described in <span class="citation" data-cites="Wooldrdige2022">@Wooldrdige2022</span>, the standard ETWFE model described in <a href="#eq-b0" class="quarto-xref">Equation&nbsp;1</a> or <a href="#eq-b1" class="quarto-xref">Equation&nbsp;2</a> identifies the average treatment effect imposing a linear parallel trends assumption. However, such assumption may not be valid in cases, such as when the dependent variable follows some limited distribution. <span class="citation" data-cites="CallawayRoth">@CallawayRoth</span> discusses a similar problem, stating that the choice of transformation of the dependent variable is crucial for the identification of the average treatment effect, and only under certain conditions would the ATT be identified for any transformation.</p>
<p>In this regard, <span class="citation" data-cites="wooldridge2022">@wooldridge2022</span> proposes that the linear ETWFE models can be adapted to allow for non-linear models, by simply imposing the linear PTA assumption only on the latent variable of the model, but not the outcome itself.</p>
<p>Consider the following transformation of the model defined by <a href="#eq-b2" class="quarto-xref">Equation&nbsp;3</a>:</p>
<p><span id="eq-e1"><span class="math display">\[E(Y_{i,t}|X,\xi_i,\xi_t) = H\left(\alpha +  \sum_{g \in G} \sum_{t=t_0}^{g-1} \theta^{pre}_{g,t} D_{i,g,t}+ \sum_{g \in G} \sum_{t=g}^{T} \theta^{post}_{g,t} D_{i,g,t} + \xi_i + \xi_t \right)
\tag{4}\]</span></span></p>
<p>This specification focuses on identifying the conditional expected value of the outcome of interest as function of the treatment status, and the individual and time fixed effects. If we assume the <span class="math inline">\(H()\)</span> is the identify function, we would be back to the linear model described by <a href="#eq-b2" class="quarto-xref">Equation&nbsp;3</a>. However, if we assume that <span class="math inline">\(H()\)</span> is a non-linear function, like exponetial for poisson, or logistic for logit models, we could estimate the average treatment effect under different assumptions, imposing only linear PTA on the latent variable of the model.</p>
<p>The <code>jwdid</code> command allows the user to specify the <code>method()</code> option to estimate models described by <a href="#eq-e1" class="quarto-xref">Equation&nbsp;4</a>, where one would specificy the regression model to be estimated, followed by the options associated with that model. For example, if we would be interested in estimating a poisson model, we would use the following syntax:</p>
<p><code>jwdid y, ivar(i) tvar(t) gvar(g) never method(poisson)</code></p>
<p>There is no restrictions on the type <code>method</code> one can use with the <code>jwdid</code> command, but it has not been tested with all possible models. The user should be aware that the <code>method()</code> option is passed directly for the model estimation step, and the user should be familiar with the syntax of the model being estimated.</p>
<p>It should be noted that when estimating non-linear models with a large number of fixed effects, one may face an incidental parameters problem. This is not generally a problem for the linear case, because the parameters of interest can be identified without explicitly estimating the fixed effects, using, for example the within transformation. However, with the exception of poisson models, fixed effects are generally estimated raising the possibility of incidental parameters. To reduce the impact of this problem, whenver <code>method()</code> is specified <code>jwdid</code> will incorporate <em>group</em> fixed effects, instead of <em>individual</em> fixed effects.</p>
<p>For the linear case with balanced data, using <em>group</em> instead of <em>individual</em> fixed effects provides numerically identical results. If panel is unbalanced the results will not be identical. In such cases, the option <code>corr</code> will create additional variables that address the difference. In the case of non-linear models, the best solution is to use <em>group</em> fixed effects. However, if one is interested in poisson models, the alterantive to group fixed effects is to use <code>ppmlhdfe</code> (<span class="citation" data-cites="correira2020">@correira2020</span>).<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> This is the state-of-the-art estimator for poisson models with fixed effects, and it is the recommended estimator for trade analysis.</p>
</section>
<section id="sec-cov" class="level3">
<h3 class="anchored" data-anchor-id="sec-cov">Extensions: Covariates</h3>
<p>As described in <span class="citation" data-cites="wooldridge">@wooldridge</span>, it is possible to include covariates in the model, by simply adding corrections that enable to easily identify the average treatment effect. However, following the literature on DID models, the implicit assumption is that covariates are time-invariant. <code>jwdid</code> does not impose any assumption on the covariates, but the user should be aware of the implications.</p>
<p>In general, when covariates are considered, the model of interest is similar to <a href="#eq-b2" class="quarto-xref">Equation&nbsp;3</a>, but adjusted for covariates:</p>
<p><span id="eq-e2"><span class="math display">\[\begin{aligned}
Y_{i,t} &amp;= \alpha +  \sum_{g \in G} \sum_{t=t_0}^{g-1} \theta^{pre}_{g,t} D_{i,g,t}+
\sum_{g \in G} \sum_{t=g}^{T} \theta^{post}_{g,t} D_{i,g,t} + \sum_{g \in G} \sum_{t=t_0}^{g-1} D_{i,g,t} \tilde x_{i}'\beta^{pre}_{g,t} +
\sum_{g \in G} \sum_{t=g}^{T} D_{i,g,t} \tilde x_{i}'\beta^{post}_{g,t} \\
&amp;+ x_{i}'\beta + \sum_{t=t_0}^{T} D_{i,t} x_{i}'\beta_t + \sum_{g\in G} D_{i,g} x_{i}'\beta_g
\xi_i + \xi_t + \varepsilon_{i,t}
\end{aligned}
\tag{5}\]</span></span></p>
<p>Where <span class="math inline">\(D_{i,t}\)</span> is a dummy variable that is equal to 1 if period is equal to <span class="math inline">\(t\)</span>, and <span class="math inline">\(D_{i,g}\)</span> is a dummmy variable that is equal to 1 if the group membership is equal to <span class="math inline">\(g\)</span>, and zero otherwise. <span class="math inline">\(\tilde x_{i}\)</span> are the within cohort and period demeaned variables. When using <code>reghdfe</code> or <code>ppmlhdfe</code> the term <span class="math inline">\(\sum_{g\in G} D_{i,g} x_{i}'\beta_g\)</span> is ommitted if all covariates are time constant.</p>
<p>Using <span class="math inline">\(\tilde x\)</span>, default option, is not necessarity for the estimation of treatment effects. However, if one uses that specification, the parameters <span class="math inline">\(\theta^{pre}_{g,t}\)</span> and <span class="math inline">\(\theta^{post}_{g,t}\)</span> still identify the average treatment effect for group <span class="math inline">\(g\)</span> at time <span class="math inline">\(t\)</span>. One could also use the untransformed covariates in <a href="#eq-e2" class="quarto-xref">Equation&nbsp;5</a>, and still be able to obtained the same group/time specific treatment effects with the post estimation commands.</p>
<p>From the user persective, <code>jwdid</code> would simply need to be called as follows:</p>
<p><code>jwdid y x, ivar(i) tvar(t) gvar(g) never [xasis]</code></p>
<p>Where <code>x</code> are all covariates of interest. If one uses the option <code>xasis</code>, the command will use the covariates without demeaning them, which may save some computation time.</p>
</section>
<section id="sec-het" class="level3">
<h3 class="anchored" data-anchor-id="sec-het">Extensions: Treatment Heterogeneity</h3>
<p>As it may be aparent from <a href="#eq-e2" class="quarto-xref">Equation&nbsp;5</a>, the number of estimated parameters can grow quickly with the number groups/cohorts, periods of analysis, and covariates. This could lead to increasing computational burden of the estimation. An alternative, which is already implemented via <code>xthdidregress</code> and <code>hdidregress</code> in Stata 18, is to estimate the model that reduces the heterogeneity of the treatment effects. Specifically, it allows treatment effects to vary across cohorts, across absolute time, or across relative time.</p>
<p>For the case without covariates, the specification of <a href="#eq-b2" class="quarto-xref">Equation&nbsp;3</a> can be modified to impose the heterogeneity restrictions as follows:</p>
<p>Time heterogeneity:</p>
<p><span id="eq-ht1"><span class="math display">\[Y_{i,t} = \alpha +  \sum_{t=t_0}^T \theta^{pre}_{t} D_{i,t,pre} + \sum_{t=t_0}^T \theta^{post}_{t}  D_{i,t,post}+ \xi_i + \xi_t + \varepsilon_{i,t}
\tag{6}\]</span></span></p>
<p>Cohort heterogeneity:</p>
<p><span id="eq-ht2"><span class="math display">\[Y_{i,t} = \alpha +  \sum_{g\in G} \theta^{pre}_{g}  D_{i,g,pre}+ \sum_{g\in G} \theta^{post}_{g} D_{i,g,post} + \xi_i + \xi_t+\varepsilon_{i,t}
\tag{7}\]</span></span></p>
<p>Event (Relative Time) heterogeneity:</p>
<p><span id="eq-ht3"><span class="math display">\[Y_{i,t} = \alpha +  \sum_{e = E_{min}}^{-2} \theta_{e} D_{i,e}+ \sum_{e = 0}^{E_{max}} \theta_{e} D_{i,e} + \xi_i + \xi_t+\varepsilon_{i,t}
\tag{8}\]</span></span></p>
<p>Where <span class="math inline">\(D_{i,t,pre}\)</span> and <span class="math inline">\(D_{i,t,post}\)</span> are dummies that take the value of 1 if observation <span class="math inline">\(i\)</span>, which is part of an eventually treated group, is not yet treated or is already treated at time <span class="math inline">\(t\)</span>, respectively. <span class="math inline">\(D_{i,g,pre}\)</span> and <span class="math inline">\(D_{i,g,post}\)</span> are dummies that take the value of 1 if observation <span class="math inline">\(i\)</span> belongs to group <span class="math inline">\(g\)</span> and is not yet treated or is already treated at time <span class="math inline">\(t\)</span>, respectively. <span class="math inline">\(D_{i,e}\)</span> is a dummy that takes the value of 1 if observation <span class="math inline">\(i\)</span> is <span class="math inline">\(e\)</span> periods relative to when treatment started. <span class="math inline">\(E_{min}\)</span> and <span class="math inline">\(E_{max}\)</span> are the minimum and maximum event periods, possible. The <em>pre</em> coefficients are only considered when the <code>never</code> option is used.</p>
<p>The <code>jwdid</code> command allows the user to specify each one of these restrictions using the <code>hettype()</code> option.</p>
<p><code>jwdid y, ivar(i) tvar(t) gvar(g) hettype(option)</code></p>
<p>Where <code>option</code> can be <code>time</code>, <code>cohort</code>, or <code>event</code>. If no option is selected, the command will estimate the model described by <a href="#eq-b2" class="quarto-xref">Equation&nbsp;3</a> which is the equivalent to allowing for full Cohort-time heterogeneity.</p>
</section>
<section id="extensions-other-options" class="level3">
<h3 class="anchored" data-anchor-id="extensions-other-options">Extensions: Other Options</h3>
<p>As described in <a href="#sec-cov" class="quarto-xref">Section&nbsp;1.3</a>, when covariates are considered in the model, the default option is to interact all covariates (or the demeaned transformations) with the same level of covariate heterogeneity. Some times, however, one may not be interested in estimating the same level of heterogeneity for all covariates. It may be possible, for example, to consider separate sets of covariates that could be interacted only with the time or the group dimensions.</p>
<p>Specifically, assume there are no variables we wish to consider for the treatment heterogeneity, but instead consider three sets of covariates: <span class="math inline">\(x^{EX}\)</span> or variables we wish to incorporate without further interactions, <span class="math inline">\(x^{T}\)</span> or variables that would be interacted with the Time variables only, and <span class="math inline">\(x^{G}\)</span> or variables that would be interacted with group indicators only. In this case the setup would be:</p>
<p><span id="eq-op1"><span class="math display">\[\begin{aligned}
Y_{i,t} &amp;= \alpha +  \sum_{g \in G} \sum_{t=t_0}^{g-1} \theta^{pre}_{g,t} D_{i,g,t}+
\sum_{g \in G} \sum_{t=g}^{T} \theta^{post}_{g,t} D_{i,g,t} \\
&amp;+ x'^{EX}_{i}\beta + \sum_{t=t_0}^{T} D_{i,t} x'^{T}_{i}\beta_t + \sum_{g\in G} D_{i,g} x'^{G}_{i}\beta_g
\xi_i + \xi_t + \varepsilon_{i,t}
\end{aligned}
\tag{9}\]</span></span></p>
<p>This specification can be estimated using the following syntax:</p>
<p><code>jwdid y , ivar(i) tvar(t) gvar(g) never exogvar(x_ex) xtvar(x_t) xgvar(x_g)</code></p>
<p>If covariates are included after <code>y</code>, they would still be treated following the specification of <a href="#eq-e2" class="quarto-xref">Equation&nbsp;5</a>, or following any of the heterogeneity restrictions described in <a href="#sec-het" class="quarto-xref">Section&nbsp;1.4</a>.</p>
<p>An advanced version of this option is the inclusion of high order fixed effects (and interactions with fixed effects) that are different from the individual and time fixed effects. It is possible to request the inclusion of those types of fixed effects using the option <code>fevar()</code>, which is only valid if one is using the default estimator method <code>reghdfe</code> or <code>ppmlhdfe</code>. In both cases, the additional fixed effects (or interactions) are included in the estimation of the model without further interactions.</p>
</section>
</section>
<section id="sec-agg" class="level2">
<h2 class="anchored" data-anchor-id="sec-agg">Post estimation: Aggregated treatment effects</h2>
<p>After the estimation of the model, under the default options, one can use the coefficients <span class="math inline">\(\theta^{post}_{g,t}\)</span> as direct estimates of the group and time specific average tretment effects on the treated. However, one may also be interested in estimating aggregated ATTs for the overall data, across groups or periods, or dynamic effects. Furthermore, when the underlying method is a non-linear model, these coefficients cannot be directly interpreted as the average treatment effect on the outcome, but only on the latent variable.</p>
<p><code>jwdid</code> comes along with the post estimation command <code>jwdid_estat</code> that can be used for that purpose. Internally, it uses the <code>margins</code> command to identify average treatment effects under the following algorithm:</p>
<ol type="1">
<li>Using the model estimates, predict the outcome of interest for all observations given the observed covariates and fixed effects. Call this <span class="math inline">\(\hat Y(obs)\)</span> or predicted outcome under the observed covariates. The model prediction could be the linear prediction, or the predicted probability in the case of logit models, or the predicted count in the case of poisson models.</li>
<li>Consider the specification <span class="citation" data-cites="eq_e2">@eq_e2</span>, and assume that all <span class="math inline">\(\theta^{post}_{g,t}\)</span> (and <span class="math inline">\(\theta^{pre}_{g,t}\)</span> if <code>never</code> is used), as well as all <span class="math inline">\(\beta^{post}\)</span> and <span class="math inline">\(\beta^{pre}\)</span> are zero, and predict the outcome of interest. Call this <span class="math inline">\(\hat Y(0)\)</span> or predicted outcome under the counterfactual scenario of no treatment.</li>
</ol>
<p>In this case, the predicted Average Treatment Effect on the Treated for observation <span class="math inline">\(i\)</span> is given by:</p>
<p><span class="math display">\[\widehat{ATT}_i = \hat Y(obs) - \hat Y(0)\]</span></p>
<p>This is zero for observations that were never treated, and nonzero for the treated-post treatment observations.<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<p>From here, any aggregated average treatment effects can be calculated as follows:</p>
<p><span class="math display">\[AGGTE_r =  \frac{ \sum_i^N\widehat{ATT}_i \times w_{i,t} \times R_{i,t}}{ \sum_i^N  w_{i,t} \times R_{i,t}}  
\]</span></p>
<p>where <span class="math inline">\(R_{i,t}\)</span> takes the value of one whenever observation <span class="math inline">\(i\)</span> fullfills the required conditions, and <span class="math inline">\(w_{i,t}\)</span> is the weight of the observation <span class="math inline">\(i\)</span> at time <span class="math inline">\(t\)</span> used in for the estimation model. <a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>. <span class="math inline">\(AGGTE\)</span> is the aggregated average treatment effect on the treated given the conditions <span class="math inline">\(R\)</span>.</p>
<p>In general, there are three types of aggregations that are implemented in the <code>jwdid_estat/estat</code> command:</p>
<ol type="1">
<li><code>estat simple</code>: This option calculates the average treatment effect on the treated for all observations that were treated at some point in time. The condition <span class="math inline">\(R\)</span> is defined as:</li>
</ol>
<p><span class="math display">\[\begin{aligned}
R_{i,t} &amp;= 1 \text{ if } t \geq g \text{ for observation } i \in g \\
R_{i,t} &amp;= 0 \text{ otherwise}
\end{aligned}
\]</span></p>
<ol start="2" type="1">
<li><code>estat group</code>: This option calculates the average treatment effect for observations that were treated at time <span class="math inline">\(g\)</span>. The condition <span class="math inline">\(R\)</span> is defined as:</li>
</ol>
<p><span class="math display">\[\begin{aligned}
R_{i,t} &amp;= 1 \text{ if } t \geq g_c \text{ for observation } i \\
R_{i,t} &amp;= 0 \text{ otherwise}
\end{aligned}
\]</span></p>
<p>where <span class="math inline">\(g_c\)</span> is a particular group/cohort of interest. <code>estat group</code> estimates this for all groups <span class="math inline">\(g\)</span> in <span class="math inline">\(G\)</span>.</p>
<ol start="3" type="1">
<li><code>estat time</code>: This option calculates the average treatment effect at time <span class="math inline">\(t\)</span> for all observations that were effectively treated at that point. The condition <span class="math inline">\(R\)</span> is defined as:</li>
</ol>
<p><span class="math display">\[\begin{aligned}
R_{i,t} &amp;= 1 \text{ if } t_c \geq g \text{ for observation } i \\
R_{i,t} &amp;= 0 \text{ otherwise}
\end{aligned}
\]</span></p>
<p>where <span class="math inline">\(t_c\)</span> is a particular time of interest. <code>estat time</code> estimates this for all times <span class="math inline">\(t\)</span> in <span class="math inline">\(T\)</span> that has at least one unit that was treated.</p>
<ol start="4" type="1">
<li><code>estat event</code>: This option calculates dynamic treatment effects, also known as event studies, using the period before treatment as the reference. When the condition `never’ is used, this approach can be used to estimate pre-treatment ATT’s, which could be used for testing PTA. The condition <span class="math inline">\(R\)</span> is defined as:</li>
</ol>
<p><span class="math display">\[\begin{aligned}
R_{i,t} &amp;= 1 \text{ if } t-g = e_c \text{ \&amp; } e \neq -1 \text{ for observation } i \\
R_{i,t} &amp;= 0 \text{ otherwise}
\end{aligned}
\]</span></p>
<p>where <span class="math inline">\(e_c\)</span> is a particular event of interest. In contrast with the previous aggregations, if option <code>never</code> was used for estimation, one could also add the option <code>pretrend</code> to run a simple PTA test with the following null hypothesis:</p>
<p><span class="math display">\[H_0: AGGTE_e = 0 \text{ for all } e &lt; -1 \text{ vs }H_1: AGGTE_e \neq 0 \text{ for some } e &lt; -1\]</span></p>
<p>Failure to reject this hypothesis is evidence in support of parallel trends assumption. Otherwise, one can use <code>test</code> command to test for the significance of specific pre-treatment ATT’s.<a href="#fn5" class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a></p>
</section>
<section id="post-estimation-other-options" class="level2">
<h2 class="anchored" data-anchor-id="post-estimation-other-options">Post estimation: Other options</h2>
<p>The <code>jwdid_estat</code>/<code>estat</code> command allows for further options that may be of interest for the user. In this section we provide a brief description of those options:</p>
<section id="weights" class="level3">
<h3 class="anchored" data-anchor-id="weights">Weights</h3>
<p>The default option for the estimation of the aggregated ATTs is to use the weights <span class="math inline">\(w_{i,t}\)</span> that were used in the estimation of the model. However, if the user wants to use different weights, it is possible to do using the following syntax:</p>
<p><code>estat [aggregation] [pw = weight]</code></p>
</section>
<section id="standard-errors" class="level3">
<h3 class="anchored" data-anchor-id="standard-errors">Standard Errors</h3>
<p><span class="citation" data-cites="wooldridge2022">@wooldridge2022</span> suggests than when one estimates standard errors for the aggregated ATTs, one should use <code>vce(unconditional)</code> option in <code>Stata</code>, to allow for uncertainty in the explanatory variables. <code>jwdid_estat</code>/<code>estat</code> does not use this approach by default, because it requires that the underlying command is able to produce Scores for the estimated model. For example, if the model was estimated using <code>method(regress)</code>, the Scores will be available, and unconditional Standard errors for the aggregated ATTs can be estimated as follows:</p>
<p><code>estat [aggregation], [vce(unconditional)]</code></p>
<p>This is not possible if one uses the default methodology <code>reghdfe</code>.</p>
</section>
<section id="other-aggregation-restrictions" class="level3">
<h3 class="anchored" data-anchor-id="other-aggregation-restrictions">Other Aggregation restrictions</h3>
<p>As described in <a href="#sec-agg" class="quarto-xref">Section&nbsp;2</a>, the default aggregation considers all observations treated observations, impossing restrictions only in terms of time, group or event dimensions. However, one may be interested in imposing further restrictions that could leverage on the use of covariates in the model specification. For example, say that one estimates a DID model with covariates using the following syntax:</p>
<p><code>jwdid y i.dx, ivar(i) tvar(t) gvar(g) never</code></p>
<p>As usual, one could request the estimation of the aggregated ATTs for the whole sample as follows:</p>
<p><code>estat [aggregation]</code></p>
<p>However, one would also be able to make the same estimation imposing the added restriction that the covariate <code>dx</code> is zero or one, using the option <code>orestriction()</code>:</p>
<p><code>estat [aggregation], orestriction(dx==0)</code></p>
<p><code>estat [aggregation], orestriction(dx==1)</code></p>
<p>The expression inside the parenthesis should be a valid Stata expression that is used when calculating the aggregated ATTs.</p>
</section>
<section id="storing-and-saving-results" class="level3">
<h3 class="anchored" data-anchor-id="storing-and-saving-results">Storing, and saving results</h3>
<p>After aggregate effects have been estimated, the user may want to store the results for further analysis or reporting. Because <code>estat</code> uses <code>margins</code> in the background, the default option is to store the results in memory as <code>r()</code> elements. Alternatively, <code>jwdid_estat</code>/<code>estat</code> allows the user to store the output of the command using three different options:</p>
<ol type="1">
<li><code>estat [aggregation], post</code>: As with margins, option <code>post</code> will “post” the results of the command to be the current estimations in memory <code>e()</code>, which can be saved as usual for further analysis.</li>
<li><code>estat [aggregation], estore(name)</code>: This option stores the results from the aggregation in memory as <code>name</code>. This is similar to using <code>estimation store name</code> after a regression command. The previously estimated results from <code>jwdid</code> are not overwritten.</li>
<li><code>estat [aggregation], esave(filename)</code>: This option saves the results from the aggregation in a file <code>filename</code>, as a <code>ster</code> file, which can be used at a later point.</li>
</ol>
</section>
<section id="plotting" class="level3">
<h3 class="anchored" data-anchor-id="plotting">Plotting</h3>
<p>After <strong>time</strong>, <strong>group</strong> or <strong>event</strong> aggregations are estimated, it is possible to request plotting those results using <code>estat plot</code>. The basic syntax is to type it after the aggregation command, with only minimal command specific options:</p>
<ol type="1">
<li><p><code>estat plot, style(style)</code>: The option <code>style</code> allows the user to select the style of the plot. The default is using a <code>rspike</code> style, but <code>rarea</code>, <code>rcap</code> and <code>rbar</code> are also available. See <code>help twoway</code> for more information on the styles.</p></li>
<li><p><code>estat plot,  pstyle1(str) color1(str) pstyle2(str) color2(str) lwidth1(str) lwidth2(str) barwidth1(str) barwidth2(str)</code>: The options <code>pstyle#</code>, <code>color#</code>, <code>lwidth#</code> and <code>barwidth#</code> can be used to alter the color and style of the lines in the plot for the pre and post treatment periods. Only <code>event</code> aggregation allows for <code>#2</code> options.</p></li>
<li><p><code>estat plot, twoway_options</code>: Most other <code>twoway</code> graph option can be used after the <code>estat plot</code> command.</p></li>
</ol>
</section>
</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Often, one can use group fixed effects instead of individual fixed effects, and would still obtain numerically identical results in the linear model case.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p> The correction implemented with <code>corr</code> is not useful to recover the coefficients from <code>ppmlhdfe</code> using <code>poisson</code> command <a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>The case of pre-treatment treated observations may be assumed to be zero if the <code>never</code> option is not used. When <code>never</code> is used, pre-treatment ATTs can be used for testing the parallel trends assumption.<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>While this is the default option, <code>estat</code> command also allow you to provide other weights for aggregation<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>It should be noticed that this test is different from the test proposed by <span class="citation" data-cites="callaway2021">@callaway2021</span>, which is based on testing <em>all</em> group/time specific ATT’s, instead of the event aggregated ones.<a href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section></div></main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
  const toggleBodyColorMode = (bsSheetEl) => {
    const mode = bsSheetEl.getAttribute("data-mode");
    const bodyEl = window.document.querySelector("body");
    if (mode === "dark") {
      bodyEl.classList.add("quarto-dark");
      bodyEl.classList.remove("quarto-light");
    } else {
      bodyEl.classList.add("quarto-light");
      bodyEl.classList.remove("quarto-dark");
    }
  }
  const toggleBodyColorPrimary = () => {
    const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
    if (bsSheetEl) {
      toggleBodyColorMode(bsSheetEl);
    }
  }
  toggleBodyColorPrimary();  
  const icon = "";
  const anchorJS = new window.AnchorJS();
  anchorJS.options = {
    placement: 'right',
    icon: icon
  };
  anchorJS.add('.anchored');
  const isCodeAnnotation = (el) => {
    for (const clz of el.classList) {
      if (clz.startsWith('code-annotation-')) {                     
        return true;
      }
    }
    return false;
  }
  const clipboard = new window.ClipboardJS('.code-copy-button', {
    text: function(trigger) {
      const codeEl = trigger.previousElementSibling.cloneNode(true);
      for (const childEl of codeEl.children) {
        if (isCodeAnnotation(childEl)) {
          childEl.remove();
        }
      }
      return codeEl.innerText;
    }
  });
  clipboard.on('success', function(e) {
    // button target
    const button = e.trigger;
    // don't keep focus
    button.blur();
    // flash "checked"
    button.classList.add('code-copy-button-checked');
    var currentTitle = button.getAttribute("title");
    button.setAttribute("title", "Copied!");
    let tooltip;
    if (window.bootstrap) {
      button.setAttribute("data-bs-toggle", "tooltip");
      button.setAttribute("data-bs-placement", "left");
      button.setAttribute("data-bs-title", "Copied!");
      tooltip = new bootstrap.Tooltip(button, 
        { trigger: "manual", 
          customClass: "code-copy-button-tooltip",
          offset: [0, -8]});
      tooltip.show();    
    }
    setTimeout(function() {
      if (tooltip) {
        tooltip.hide();
        button.removeAttribute("data-bs-title");
        button.removeAttribute("data-bs-toggle");
        button.removeAttribute("data-bs-placement");
      }
      button.setAttribute("title", currentTitle);
      button.classList.remove('code-copy-button-checked');
    }, 1000);
    // clear code selection
    e.clearSelection();
  });
  function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
    const config = {
      allowHTML: true,
      maxWidth: 500,
      delay: 100,
      arrow: false,
      appendTo: function(el) {
          return el.parentElement;
      },
      interactive: true,
      interactiveBorder: 10,
      theme: 'quarto',
      placement: 'bottom-start',
    };
    if (contentFn) {
      config.content = contentFn;
    }
    if (onTriggerFn) {
      config.onTrigger = onTriggerFn;
    }
    if (onUntriggerFn) {
      config.onUntrigger = onUntriggerFn;
    }
    window.tippy(el, config); 
  }
  const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
  for (var i=0; i<noterefs.length; i++) {
    const ref = noterefs[i];
    tippyHover(ref, function() {
      // use id or data attribute instead here
      let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
      try { href = new URL(href).hash; } catch {}
      const id = href.replace(/^#\/?/, "");
      const note = window.document.getElementById(id);
      return note.innerHTML;
    });
  }
  const xrefs = window.document.querySelectorAll('a.quarto-xref');
  const processXRef = (id, note) => {
    // Strip column container classes
    const stripColumnClz = (el) => {
      el.classList.remove("page-full", "page-columns");
      if (el.children) {
        for (const child of el.children) {
          stripColumnClz(child);
        }
      }
    }
    stripColumnClz(note)
    if (id === null || id.startsWith('sec-')) {
      // Special case sections, only their first couple elements
      const container = document.createElement("div");
      if (note.children && note.children.length > 2) {
        container.appendChild(note.children[0].cloneNode(true));
        for (let i = 1; i < note.children.length; i++) {
          const child = note.children[i];
          if (child.tagName === "P" && child.innerText === "") {
            continue;
          } else {
            container.appendChild(child.cloneNode(true));
            break;
          }
        }
        if (window.Quarto?.typesetMath) {
          window.Quarto.typesetMath(container);
        }
        return container.innerHTML
      } else {
        if (window.Quarto?.typesetMath) {
          window.Quarto.typesetMath(note);
        }
        return note.innerHTML;
      }
    } else {
      // Remove any anchor links if they are present
      const anchorLink = note.querySelector('a.anchorjs-link');
      if (anchorLink) {
        anchorLink.remove();
      }
      if (window.Quarto?.typesetMath) {
        window.Quarto.typesetMath(note);
      }
      // TODO in 1.5, we should make sure this works without a callout special case
      if (note.classList.contains("callout")) {
        return note.outerHTML;
      } else {
        return note.innerHTML;
      }
    }
  }
  for (var i=0; i<xrefs.length; i++) {
    const xref = xrefs[i];
    tippyHover(xref, undefined, function(instance) {
      instance.disable();
      let url = xref.getAttribute('href');
      let hash = undefined; 
      if (url.startsWith('#')) {
        hash = url;
      } else {
        try { hash = new URL(url).hash; } catch {}
      }
      if (hash) {
        const id = hash.replace(/^#\/?/, "");
        const note = window.document.getElementById(id);
        if (note !== null) {
          try {
            const html = processXRef(id, note.cloneNode(true));
            instance.setContent(html);
          } finally {
            instance.enable();
            instance.show();
          }
        } else {
          // See if we can fetch this
          fetch(url.split('#')[0])
          .then(res => res.text())
          .then(html => {
            const parser = new DOMParser();
            const htmlDoc = parser.parseFromString(html, "text/html");
            const note = htmlDoc.getElementById(id);
            if (note !== null) {
              const html = processXRef(id, note);
              instance.setContent(html);
            } 
          }).finally(() => {
            instance.enable();
            instance.show();
          });
        }
      } else {
        // See if we can fetch a full url (with no hash to target)
        // This is a special case and we should probably do some content thinning / targeting
        fetch(url)
        .then(res => res.text())
        .then(html => {
          const parser = new DOMParser();
          const htmlDoc = parser.parseFromString(html, "text/html");
          const note = htmlDoc.querySelector('main.content');
          if (note !== null) {
            // This should only happen for chapter cross references
            // (since there is no id in the URL)
            // remove the first header
            if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
              note.children[0].remove();
            }
            const html = processXRef(null, note);
            instance.setContent(html);
          } 
        }).finally(() => {
          instance.enable();
          instance.show();
        });
      }
    }, function(instance) {
    });
  }
      let selectedAnnoteEl;
      const selectorForAnnotation = ( cell, annotation) => {
        let cellAttr = 'data-code-cell="' + cell + '"';
        let lineAttr = 'data-code-annotation="' +  annotation + '"';
        const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
        return selector;
      }
      const selectCodeLines = (annoteEl) => {
        const doc = window.document;
        const targetCell = annoteEl.getAttribute("data-target-cell");
        const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
        const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
        const lines = annoteSpan.getAttribute("data-code-lines").split(",");
        const lineIds = lines.map((line) => {
          return targetCell + "-" + line;
        })
        let top = null;
        let height = null;
        let parent = null;
        if (lineIds.length > 0) {
            //compute the position of the single el (top and bottom and make a div)
            const el = window.document.getElementById(lineIds[0]);
            top = el.offsetTop;
            height = el.offsetHeight;
            parent = el.parentElement.parentElement;
          if (lineIds.length > 1) {
            const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
            const bottom = lastEl.offsetTop + lastEl.offsetHeight;
            height = bottom - top;
          }
          if (top !== null && height !== null && parent !== null) {
            // cook up a div (if necessary) and position it 
            let div = window.document.getElementById("code-annotation-line-highlight");
            if (div === null) {
              div = window.document.createElement("div");
              div.setAttribute("id", "code-annotation-line-highlight");
              div.style.position = 'absolute';
              parent.appendChild(div);
            }
            div.style.top = top - 2 + "px";
            div.style.height = height + 4 + "px";
            div.style.left = 0;
            let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
            if (gutterDiv === null) {
              gutterDiv = window.document.createElement("div");
              gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
              gutterDiv.style.position = 'absolute';
              const codeCell = window.document.getElementById(targetCell);
              const gutter = codeCell.querySelector('.code-annotation-gutter');
              gutter.appendChild(gutterDiv);
            }
            gutterDiv.style.top = top - 2 + "px";
            gutterDiv.style.height = height + 4 + "px";
          }
          selectedAnnoteEl = annoteEl;
        }
      };
      const unselectCodeLines = () => {
        const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
        elementsIds.forEach((elId) => {
          const div = window.document.getElementById(elId);
          if (div) {
            div.remove();
          }
        });
        selectedAnnoteEl = undefined;
      };
        // Handle positioning of the toggle
    window.addEventListener(
      "resize",
      throttle(() => {
        elRect = undefined;
        if (selectedAnnoteEl) {
          selectCodeLines(selectedAnnoteEl);
        }
      }, 10)
    );
    function throttle(fn, ms) {
    let throttle = false;
    let timer;
      return (...args) => {
        if(!throttle) { // first call gets through
            fn.apply(this, args);
            throttle = true;
        } else { // all the others get throttled
            if(timer) clearTimeout(timer); // cancel #2
            timer = setTimeout(() => {
              fn.apply(this, args);
              timer = throttle = false;
            }, ms);
        }
      };
    }
      // Attach click handler to the DT
      const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
      for (const annoteDlNode of annoteDls) {
        annoteDlNode.addEventListener('click', (event) => {
          const clickedEl = event.target;
          if (clickedEl !== selectedAnnoteEl) {
            unselectCodeLines();
            const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
            if (activeEl) {
              activeEl.classList.remove('code-annotation-active');
            }
            selectCodeLines(clickedEl);
            clickedEl.classList.add('code-annotation-active');
          } else {
            // Unselect the line
            unselectCodeLines();
            clickedEl.classList.remove('code-annotation-active');
          }
        });
      }
  const findCites = (el) => {
    const parentEl = el.parentElement;
    if (parentEl) {
      const cites = parentEl.dataset.cites;
      if (cites) {
        return {
          el,
          cites: cites.split(' ')
        };
      } else {
        return findCites(el.parentElement)
      }
    } else {
      return undefined;
    }
  };
  var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
  for (var i=0; i<bibliorefs.length; i++) {
    const ref = bibliorefs[i];
    const citeInfo = findCites(ref);
    if (citeInfo) {
      tippyHover(citeInfo.el, function() {
        var popup = window.document.createElement('div');
        citeInfo.cites.forEach(function(cite) {
          var citeDiv = window.document.createElement('div');
          citeDiv.classList.add('hanging-indent');
          citeDiv.classList.add('csl-entry');
          var biblioDiv = window.document.getElementById('ref-' + cite);
          if (biblioDiv) {
            citeDiv.innerHTML = biblioDiv.innerHTML;
          }
          popup.appendChild(citeDiv);
        });
        return popup.innerHTML;
      });
    }
  }
});
</script>
</div> <!-- /content -->




</body></html>